package org.jeecg.common.util.word;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.lowagie.text.Phrase;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.hdgf.chunks.Chunk;
import org.apache.poi.hssf.usermodel.HeaderFooter;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.Units;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.w3c.dom.Node;

import java.awt.*;
import java.io.*;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.jeecg.common.constant.enums.FileTypeEnum.*;

public class WordUtil {

    /**
     * 替换模板中的占位符
     *
     * @param document    Word 文档对象
     * @param placeholder 要替换的占位符文本
     * @param replacement 替换成的文本
     */
    public static void replaceWithNewlines(XWPFDocument document, String placeholder, String replacement) {
        // 预处理换行符
        String[] lines = replacement.split("\n");

        for (XWPFParagraph paragraph : document.getParagraphs()) {
            List<XWPFRun> runs = paragraph.getRuns();
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String text = run.getText(0);
                if (text != null && text.contains(placeholder)) {
                    paragraph.removeRun(i);
                    // 循环处理每个换行符后的部分
                    for (int k = 0; k < lines.length; k++) {
                        XWPFRun run2 = paragraph.createRun();
                        run2.setText(lines[k]);
                        run2.setStyle("44");

                        // 如果不是最后一行，添加换行符
                        if (k < lines.length - 1) {
                            run2.addBreak();  // 强制换行
                        }
                    }
                    break;
                }
            }
        }
    }



    /**
     * 替换模板中的占位符
     *
     * @param document    Word 文档对象
     * @param placeholder 要替换的占位符文本
     * @param replacement 替换成的文本
     */
    public static void replaceText(XWPFDocument document, String placeholder, String replacement) {
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            for (XWPFRun run : paragraph.getRuns()) {
                String text = run.getText(0);
                if (text != null && text.contains(placeholder)) {
                    text = text.replace(placeholder, replacement);
                    run.setText(text, 0);
                }
            }
        }
    }

    /**
     * 替换模板中的占位符
     *
     * @param document    Word 文档对象
     * @param placeholder 要替换的占位符文本
     * @param maps
     */
    public static void replaceSpe(Integer titleRow, Integer titleStart, String titleStyle, XWPFDocument document, String placeholder, Map<String, List<Object>> maps) {
        // 遍历所有段落
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (int m = 0; m < paragraphs.size(); m++) {
            XWPFParagraph paragraph = paragraphs.get(m);
            for (XWPFRun run : paragraph.getRuns()) {
                String text = run.getText(0);
                if (text != null && text.contains(placeholder)) {
                    // 如果找到占位符，开始替换
                    int i = 0;
                    for (String key : maps.keySet()) {
                        // 创建一个新的段落对象
                        XWPFParagraph paragraph1 = document.insertNewParagraph(paragraph.getCTP().newCursor());
                        paragraph1.setStyle(titleStyle); //标题2格式
                        XWPFRun titleRun2 = paragraph1.createRun();
                        titleRun2.setText(titleRow + "." + (i + titleStart) + key); // 设置标题文本

                        CTBookmark ctBookmark = paragraph1.getCTP().addNewBookmarkStart();
                        long id = IdWorker.getId();
                        ctBookmark.setId(BigInteger.valueOf(id));
                        ctBookmark.setName("Toc" + i + key);
                        CTMarkupRange ctMarkupRange = paragraph1.getCTP().addNewBookmarkEnd();
                        ctMarkupRange.setId(BigInteger.valueOf(id));

                        for (Object o : maps.get(key)) {
                            if (o instanceof String) {
                                if (((String) o).startsWith("表" + titleRow + "-")) {
                                    //添加题注 表
                                    XWPFParagraph contentParagraph = document.insertNewParagraph(paragraph.getCTP().newCursor());
//                                    contentParagraph.setAlignment(ParagraphAlignment.CENTER);
                                    contentParagraph.setStyle("46"); //设置为表头格式(原本表头的格式)
                                    XWPFRun contentRun = contentParagraph.createRun();
                                    contentRun.setText((String) o); // 设置内容文本
                                } else {
                                    // 添加内容
                                    XWPFParagraph contentParagraph = document.insertNewParagraph(paragraph.getCTP().newCursor());
                                    contentParagraph.setStyle("8"); //设置为正文文本格式
                                    XWPFRun contentRun = contentParagraph.createRun();
                                    contentRun.setText((String) o); // 设置内容文本
                                }
                            } else if (o instanceof List) {
                                //插入表格
                                XWPFTable table = document.insertNewTbl(paragraph.getCTP().newCursor());
                                table.setTableAlignment(TableRowAlign.CENTER);
                                //填充表格
                                fillTableWithExternalData(table, (List<List<String>>) o, false, false, 1);
                                table.removeRow(0);
                            }
                        }
                        i++;
                    }
                    run.setText(text.replace(placeholder, ""), 0);
                }
            }
        }
    }

    /**
     * 替换模板中表格的占位符
     *
     * @param document    Word 文档对象
     * @param placeholder 要替换的占位符文本
     * @param replacement 替换成的文本
     */
    public static void replaceTableText(XWPFDocument document, String placeholder, String replacement) {
        List<XWPFTable> tables = document.getTables();
        if (tables.size() == 0) {
            return;
        } else {
            //循环表格
            for (int i = 0; i < tables.size(); i++) {
                XWPFTable table = tables.get(i);
                //循环表格的行
                for (int j = 0; j < table.getRows().size(); j++) {
                    XWPFTableRow row = table.getRow(j);
                    //循环表格的列
                    for (int k = 0; k < row.getTableCells().size(); k++) {
                        //获取段落 循环段落
                        List<XWPFParagraph> paragraphs = row.getCell(k).getParagraphs();
                        for (XWPFParagraph paragraph : paragraphs) {
                            //获取run
                            for (XWPFRun run : paragraph.getRuns()) {
                                String text = run.getText(0);
                                //获取内容
                                if (text != null && text.contains(placeholder)) {
                                    if (StringUtils.isEmpty(replacement)) {
                                        text = text.replace(placeholder, "暂无");
                                    } else {
                                        text = text.replace(placeholder, replacement);
                                    }
                                    run.setText(text, 0);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换模板中表格的占位符为图片
     *
     * @param document    Word 文档对象
     * @param placeholder 要替换的占位符文本
     * @param picPath 替换成的图片地址picPath
     * @param width 宽
     * @param height 高
     */
    public static void replaceTableTextToImage(XWPFDocument document, String placeholder, String picPath, int width, int height) {
        List<XWPFTable> tables = document.getTables();
        if (tables.size() == 0) {
            return;
        } else {
            //循环表格
            for (int i = 0; i < tables.size(); i++) {
                XWPFTable table = tables.get(i);
                //循环表格的行
                for (int j = 0; j < table.getRows().size(); j++) {
                    XWPFTableRow row = table.getRow(j);
                    //循环表格的列
                    for (int k = 0; k < row.getTableCells().size(); k++) {
                        //获取段落 循环段落
                        List<XWPFParagraph> paragraphs = row.getCell(k).getParagraphs();
                        for (XWPFParagraph paragraph : paragraphs) {
                            //获取run
                            for (XWPFRun run : paragraph.getRuns()) {
                                String text = run.getText(0);
                                //获取内容
                                if (text != null && text.contains(placeholder)) {
                                    // 找到占位符，替换为图片
                                    try (FileInputStream imageStream = new FileInputStream(picPath)) {
                                        // 删除占位符文本
                                        run.setText(run.getText(0).replace(placeholder, ""), 0);
                                        if (picPath.endsWith(".png")) {
                                            // 在此位置插入图片
                                            run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_PNG, "image.png", Units.toEMU(width), Units.toEMU(height));
                                        } else if (picPath.endsWith(".jpg")) {
                                            run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_JPEG, "image.jpg", Units.toEMU(width), Units.toEMU(height));
                                        }
                                    } catch (InvalidFormatException | IOException e) {
                                        System.err.println("图片插入失败: " + e.getMessage());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换模板中的占位符
     *
     * @param document    Word 文档对象
     * @param placeholder 要替换的占位符文本
     * @param replacement 替换成的文本
     */
    public static void replaceText(XWPFDocument document, String placeholder, String replacement, boolean type) {
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            for (XWPFRun run : paragraph.getRuns()) {
                String text = run.getText(0);
                if (text != null && text.contains(placeholder)) {
                    text = text.replace(placeholder, replacement);
                    run.setText(text, 0);
                    if (type) {
                        // 设置字体为黑体
                        run.setFontFamily("Arial Black");

                        // 设置居中对齐
                        paragraph.setAlignment(ParagraphAlignment.CENTER);
                    }
                }
            }
        }
    }

    /**
     * 移除模板中的占位符
     *
     * @param document    Word 文档对象
     * @param placeholder 要替换的占位符文本
     */
    public static void removeText(XWPFDocument document, String placeholder) {
        for (int i = 0; i < document.getParagraphs().size(); i++) {
            for (XWPFRun run : document.getParagraphs().get(i).getRuns()) {
                String text = run.getText(0);
                if (text != null && text.contains(placeholder)) {
                    document.removeBodyElement(i + 2);
                }
            }
        }
    }

    /**
     * 插入表格到模板的指定位置
     *
     * @param document
     * @param placeholder
     * @param externalData
     */
    public static void insertTableInTemplate(XWPFDocument document, String placeholder, List<List<String>> externalData, boolean vMerge, boolean hMerge, int rowColor) {
        // 查找占位符并在该位置插入表格
        boolean tableInserted = false;

        for (int i = 0; i < document.getParagraphs().size(); i++) {
            XWPFParagraph paragraph = document.getParagraphs().get(i);
            for (XWPFRun run : paragraph.getRuns()) {
                String text = run.getText(0);
                // 查找占位符
                if (text != null && text.contains(placeholder)) {
                    //插入表格
                    XWPFTable table = document.insertNewTbl(paragraph.getCTP().newCursor());
                    table.setTableAlignment(TableRowAlign.CENTER);
                    //填充表格
                    fillTableWithExternalData(table, externalData, vMerge, hMerge, rowColor);

                    table.removeRow(0);

                    // 删除占位符文本
                    run.setText(run.getText(0).replace(placeholder, ""), 0);

                    tableInserted = true;
                    break;
                }
            }
            if (tableInserted) break; // 只插入一次，跳出循环
        }
    }

    /**
     * 动态填充表格数据
     *
     * @param table
     * @param externalData
     */
    public static void fillTableWithExternalData(XWPFTable table, List<List<String>> externalData, boolean vMerge, boolean hMerge, int rowColor) {
        //i是行
        for (int i = 0; i < externalData.size(); i++) {
            XWPFTableRow row = table.createRow(); // 创建新行
            List<String> rowData = externalData.get(i);
            //j是列
            for (int j = 0; j < rowData.size(); j++) {
                if (j >= row.getTableCells().size()) {
                    row.createCell(); // 创建单元格
                }

                XWPFTableCell cell = row.getCell(j);
                // 获取该单元格的第一个段落
                XWPFParagraph paragraph = cell.getParagraphs().isEmpty() ? cell.addParagraph() : cell.getParagraphs().get(0);

                // 设置水平居中
                paragraph.setAlignment(ParagraphAlignment.CENTER);

                // 设置垂直居中
                cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                //如果包含\n  换行
                if (rowData.get(j) != null) {
                    if (rowData.get(j).contains("\n")) {
                        // 如果包含换行符，分成多个部分
                        String[] parts = rowData.get(j).split("\n");
                        // 循环处理每个换行符后的部分
                        for (int k = 0; k < parts.length; k++) {
                            XWPFRun run = paragraph.createRun();
                            run.setText(parts[k]);

                            // 如果不是最后一行，添加换行符
                            if (k < parts.length - 1) {
                                run.addBreak();  // 强制换行
                            }
                        }
                    } else {
                        cell.setText(rowData.get(j));
                    }
                }
//                // 在单元格中添加数据
//                XWPFRun run = paragraph.createRun();
//                run.setText(rowData.get(j)); // 将数据添加到段落


                //设置背景颜色为灰色
                if (i < rowColor) {
                    // 使用 setShading 方法设置底纹颜色 (背景颜色)
                    CTShd ctShd = cell.getCTTc().addNewTcPr().addNewShd();
                    ctShd.setFill("D0CECE"); // 设置背景颜色为黄色，使用十六进制颜色代码
                }

                //合并列 并且 只合并前两列
                if (vMerge && j < 2) {
                    //从第二行开始 查询每一列数据和上一列数据是否相同 如果相同就合并 不同就重置合并头
                    if (i > 0 && rowData.get(j).equals(externalData.get(i - 1).get(j))) {
                        row.getCell(j).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
                    } else {
                        row.getCell(j).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
                    }
                }

                //合并行 只合并前两行
                if (hMerge && i < 2) {
                    if (j > 1 && rowData.get(j).equals(rowData.get(j - 1))) {
                        row.getCell(j).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
                    } else {
                        row.getCell(j).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
                    }

                    //从第二行开始 查询每一列数据和上一列数据是否相同 如果相同就合并 不同就重置合并头
                    if (i > 0 && rowData.get(j).equals(externalData.get(i - 1).get(j))) {
                        row.getCell(j).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
                    } else {
                        row.getCell(j).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
                    }
                }
            }
        }
    }

    // 清除段落的所有缩进和样式设置
    private static void clearParagraphFormatting(XWPFParagraph paragraph) {
        // 清除样式
        paragraph.setStyle("");
        // 设置首行缩进为0
        paragraph.setIndentationFirstLine(0);
        // 设置左缩进为0
        paragraph.setIndentationLeft(0);
        // 设置右缩进为0
        paragraph.setIndentationRight(0);


        // 手动操作底层 XML 元素，清除缩进
        CTP ctp = paragraph.getCTP();
        CTPPr ppr = ctp.getPPr();
        if (ppr == null) {
            ppr = ctp.addNewPPr();  // 确保 PPr 存在
        }

        // 获取并清除 CTInd（缩进设置）
        CTInd ind = ppr.getInd();
        if (ind == null) {
            ind = ppr.addNewInd();  // 如果没有，创建一个新的
        }
        ind.setFirstLine(BigInteger.valueOf(0));  // 清除首行缩进
        ind.setLeft(BigInteger.valueOf(0));       // 清除左缩进
        ind.setRight(BigInteger.valueOf(0));      // 清除右缩进
    }

    /**
     * 插入图片
     *
     * @param document
     * @param placeholder
     * @param picPath
     */
    public static void insertImg(XWPFDocument document, String placeholder, String picPath, int width, int height) {
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            for (XWPFRun run : paragraph.getRuns()) {
                if (run.getText(0) != null && run.getText(0).contains(placeholder)) {
                    // 找到占位符，替换为图片
                    try (FileInputStream imageStream = new FileInputStream(picPath)) {
                        // 删除占位符文本
                        run.setText(run.getText(0).replace(placeholder, ""), 0);

                        if (picPath.endsWith(".png")) {
                            // 在此位置插入图片
                            run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_PNG, "image.png", Units.toEMU(width), Units.toEMU(height));
                        } else if (picPath.endsWith(".jpg")) {
                            run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_JPEG, "image.jpg", Units.toEMU(width), Units.toEMU(height));
                        }
                    } catch (InvalidFormatException | IOException e) {
                        System.err.println("图片插入失败: " + e.getMessage());
                    }
                }
            }
        }
    }


    public static String getStyleId(XWPFDocument document, String placeholder) {
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            for (XWPFRun run : paragraph.getRuns()) {
                if (run.getText(0) != null && run.getText(0).contains(placeholder)) {
                    String styleID = paragraph.getStyleID();
//                    System.out.println(styleID);
                    return styleID;
                }
            }
        }
        return null;
    }


    /**
     * 获取目录段落信息
     *
     * @param document word对象
     * @return 目录段落
     */
    private static XWPFParagraph getTocParagraph(XWPFDocument document) {
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            List<XWPFRun> runs = paragraph.getRuns();
            if (CollectionUtils.isNotEmpty(runs)) {
                for (XWPFRun run : runs) {
                    CTText[] instrTextArray = run.getCTR().getInstrTextArray();
                    for (CTText ctText : instrTextArray) {
                        if (ctText.getStringValue().trim().startsWith("TOC \\o \"1-")) {
//                            System.out.println(ctText.getStringValue());
//                            System.out.println(paragraph.getParagraphText());
                            ctText.setStringValue(" TOC \\o \"1-2\" \\h \\z \\u ");
                            document.enforceUpdateFields();
                            return paragraph;
                        }
                    }
                }
            }
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        String tempPath = "D:\\代码生成图测试\\foot1859145652096995329.docx"; //模板文件路径
        String targetPath2 = "D:\\代码生成图测试\\test2.docx";//生成文件路径

        FileInputStream fis = new FileInputStream(tempPath);
        XWPFDocument doc = new XWPFDocument(fis);


        getCTSDT(doc);

//        com.aspose.words.Document document1 = new com.aspose.words.Document(fis);
//        document1.updateFields();

        // 5. 保存修改后的文档
        FileOutputStream fos = new FileOutputStream(targetPath2);
        doc.write(fos);
//        document1.save(targetPath2);

        // 关闭文件流
        doc.close();
//        fos.close();
        fis.close();
//        }
    }

    public static void getCTSDT(XWPFDocument document) {
        CTSdtBlock block = document.getDocument().getBody().addNewSdt();
        CustomTOC toc = new CustomTOC(block);
//        toc.creatToc();

        Iterator var3 = document.getParagraphsIterator();

        while (var3.hasNext()) {
            ;
            XWPFParagraph par = (XWPFParagraph) var3.next();
            String parStyle = par.getStyle();
            if (parStyle != null && ("2".equals(parStyle) || "3".equals(parStyle) || "4".equals(parStyle))) {
                for (CTBookmark ctBookmark : par.getCTP().getBookmarkStartList()) {
                    int level = Integer.parseInt(par.getStyle());
                    if (ctBookmark.getName().toLowerCase().startsWith("_toc")) {
                        toc.addRow(level, par, ctBookmark.getName());
                        break;
                    } else if (ctBookmark.getName().toLowerCase().startsWith("toc")) {
                        toc.addRow(level, par, "\"" + ctBookmark.getName() + "\"");
                        break;
                    }
                }
            }
        }
    }

    public static void updateToc(String fileName) throws Exception {
        Class<?> aClass = Class.forName("com.aspose.words.zzXyu");
        java.lang.reflect.Field zzYAC = aClass.getDeclaredField("zzZXG");
        zzYAC.setAccessible(true);

        java.lang.reflect.Field modifiersField = zzYAC.getClass().getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(zzYAC, zzYAC.getModifiers() & ~Modifier.FINAL);
        zzYAC.set(null, new byte[]{76, 73, 67, 69, 78, 83, 69, 68});

        com.aspose.words.Document doc = new com.aspose.words.Document(fileName);
        doc.updateFields(); //更新域，会更新样式
        doc.updatePageLayout();
        doc.updateFields();
        doc.save(fileName);
    }
}
